using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace ScannerLib.FrameGrabber
{
    public static class FrameWriter 
    {
        public static int Sqr(byte b)
        {
            return ((int)b) * ((int)b);
        }

        public static Color GrayscaleValue(Color c)
        {
            byte  g = (byte)Math.Min(255.0, Math.Sqrt((Sqr(c.R) + Sqr(c.G) + Sqr(c.B))) * 255.0 / 441.672955930063709849498817084);

            return Color.FromArgb(g, g, g);
        }

        public static void AssertFormat(bool cond)
        {
            if (!cond)
                throw new Exception("Invalid file format");
        }

        public static string ReadLine(FileStream fs)
        {
            StringBuilder sb = new StringBuilder();
            byte b;
            while ((b = (byte)fs.ReadByte()) != (byte)'\n')
            {
                sb.Append((char)b);
            }

            return sb.ToString();
        }

        public static Bitmap ReadPGM(string fileName)
        {
            FileStream fs = null;

            try
            {
                fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);

                string s = ReadLine(fs);

                AssertFormat(s.Equals("P5"));

                while( true )
                {
                    s = ReadLine(fs);
                    if (s.Length == 0 || s[0] == '#')
                        continue;

                    break;
                }

                int width, height;
                string[] sWH = s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                width = Convert.ToInt32(sWH[0]);
                height = Convert.ToInt32(sWH[1]);

                s = ReadLine(fs);

                int colors;
                colors = Convert.ToInt32(s);

                Bitmap b = new Bitmap(width, height,PixelFormat.Format24bppRgb);
                
                for( int i=0; i <height; i ++ )
                    for (int j = 0; j < width; j++)
                    {
                        double color = fs.ReadByte();
                        int outColor = (int)(color * 255 / colors);
                        b.SetPixel(j, i, Color.FromArgb(outColor, outColor, outColor));
                    }

                fs.Close();
                fs.Dispose();

                return b;

            }
            catch
            {
                if (fs != null)
                {
                    fs.Close();
                    fs.Dispose();
                    
                }

                throw;
            }

        }

        public unsafe static void WritePGM(string fileName, int width, int height, int stride, int pixelWidth, int rIndex, int gIndex, int bIndex, IntPtr ptr)
        {
            byte* data = (byte*)ptr.ToPointer();
            byte* rowPointer = data;
            FileStream file = null;
            
            try
            {
                file = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);

                byte[] magick = new byte[] { (byte)'P', (byte)'5', (byte)'\n' };
                file.Write(magick,0,3);
                

                byte [] fileData = Encoding.ASCII.GetBytes(string.Format("{0} {1}\n",width,height));
                file.Write(fileData, 0, fileData.Length);

                fileData = Encoding.ASCII.GetBytes(string.Format("{0}\n", 255));
                file.Write(fileData, 0, fileData.Length);

                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        int rgb = Sqr(*(data + rIndex)) + Sqr(*(data + gIndex)) + Sqr(*(data + bIndex));
                        byte brgb = (byte)(255 * (Math.Sqrt(rgb) / 441.672955930063709849498817084));

                        file.WriteByte(brgb);

                        data = data + pixelWidth;
                    }

                    data = rowPointer + stride;
                    rowPointer = data;
                }

                file.Close();
                file = null;
            }
            catch (Exception ex)
            {
                
                if (file != null)
                {
                    file.Close();
                    file.Dispose();
                }
                throw ex;
            }
        }

        public unsafe static void WritePGM(string fileName, Bitmap bitmap)
        {
            BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            WritePGM(fileName, bd.Width, bd.Height, bd.Stride, 3, 0, 1, 2, bd.Scan0);

            bitmap.UnlockBits(bd);
        }
    }
}
